
本篇介紹 ES2021 (ES12) 提供的 String.prototype.replaceAll()。
將一個字串中的指定子字串,取代成另一個字串,是很常見的字串處理情境。
例如:要將 URL 的 query 字串 q=query+string+parameters 中的 + 字元替換成空白字元:
// 原字串
'q=query+string+parameters'
// 替換成
'q=query string parameters'
常見有以下作法:
String.prototype.replace()
String.prototype.split() + Array.prototype.join()
下面分別說明這兩種作法的小問題。
String.prototype.replace()若要一次替換多個子字串,String.prototype.replace() 的第一個參數只能使用設定 global flag 的 RegExp,而不是用字串。因為字串只能替換第一個子字串,不能一次替換多個子字串。
let query = 'q=query+string+parameters';
let queryWithSpaces = query.replace(/\+/g, ' ');
console.log(queryWithSpaces);
// q=query string parameters
這種方法的缺點是要用 RegExp,並且是轉義過的字元,像此範例用的是轉義過的 + 字元 (因為在 RegExp 的 pattern 中,+ 有特殊的意義,代表 match 一個以上)。
String.prototype.split() + Array.prototype.join()另一種常見的作法是同時使用 String.prototype.split() 和 Array.prototype.join()
let query = 'q=query+string+parameters';
let queryWithSpaces = query.split('+').join(' ');
console.log(queryWithSpaces);
// q=query string parameters
這種方法雖然可以不用處理跳脫字元 (escaping),但需要先將字串拆成包含多個字串的陣列,然後再將這些字串拼起來。
所以可以看到以上這些方法的小問題,就是不夠直覺。原本只是想將所有的 + 字元,全部改為空白的簡單需求,但因為 JavaScript 過去的限制,只能用一些獨特的小技巧才能處理 QQ。
那有沒有更直覺的作法?這就是本篇要介紹的 String.prototype.replaceAll() 派上用場的時刻!
String.prototype.replaceAll()把前面的範例換成 String.prototype.replaceAll():
let query = 'q=query+string+parameters';
let queryWithSpaces = query.replaceAll('+', ' ');
console.log(queryWithSpaces);
// q=query string parameters
就這樣!很簡單吧!完全不用說明你就會了 XD
String.prototype.replace() vs. String.prototype.replaceAll()兩者的 signature 一樣 (即參數名稱、參數數量一樣):
String.prototype.replace(searchValue, replaceValue)
String.prototype.replaceAll(searchValue, replaceValue)
但兩者的行為有些不同:
searchValue 是字串時:
replace() 只會替換第一個 searchValue
replaceAll() 會替換所有 searchValue
searchValue 不是設定 global flag 的 RegExp 時:
replace() 只會替換第一個 searchValue
replaceAll() 會拋出 TypeError exception,因為要避免與 replaceAll() 的行為不符合 (即不是全部替換)let query = 'q=query+string+parameters';
query.replaceAll(/\+/, ' ');
// TypeError: String.prototype.replaceAll called with a non-global RegExp argument
若 searchValue 是設定 global flag 的 RegExp 時,兩著的行為一樣:
let query = 'q=query+string+parameters';
let queryWithSpaces1 = query.replace(/\+/g, ' ');
console.log(queryWithSpaces1);
// q=query string parameters
let queryWithSpaces2 = query.replaceAll(/\+/g, ' ');
console.log(queryWithSpaces2);
// q=query string parameters
雖然兩者的行為一致,但應該很少會在
replaceAll使用 RegExp 吧?
String.prototype.replaceAll | 2ality